﻿using System;
using System.Collections.Generic;
using Excel = Microsoft.Office.Interop.Excel;

namespace QAToolsAddin {
    static class Undo {
        private class UndoObject {
            public Excel.Range Area;
            public object[,] Data;
            public object NumberFormat;
        }

        public delegate void SetEnabled_Delegate(bool enable);

        private static readonly UndoObjectStack _undoObjects = new UndoObjectStack(6);

        public static event SetEnabled_Delegate SetButtonEnabled;

        public static void AddUndoArea(Excel.Range area) {
            _undoObjects.Push(new UndoObject {
                Area = area,
                Data = ExcelArray<object>.Get(area.Formula),
                NumberFormat = area.NumberFormat
            });
            SetButtonEnabled(true);
        }

        public static void UndoLastArea() {
            if (_undoObjects == null || _undoObjects.Count == 0) {
                return;
            }
            UndoObject obj = _undoObjects.Pop();
            try {
                if (obj.Area.NumberFormat is string && !(obj.NumberFormat is System.DBNull))
                    obj.Area.NumberFormat = obj.NumberFormat;
            } catch { }
            try {
                obj.Area.Formula = obj.Data;
            } catch { }
            if (_undoObjects.Count == 0)
                SetButtonEnabled(false);
        }

        public static void Clear() {
            _undoObjects.Clear();
            SetButtonEnabled(false);
        }

        private class UndoObjectStack {
            private readonly int _max;
            private readonly LinkedList<UndoObject> _list;

            public UndoObjectStack(int maxSize) {
                _max = maxSize;
                _list = new LinkedList<UndoObject>();
            }

            public void Push(UndoObject value) {
                if (_list.Count == _max)
                    _list.RemoveLast();
                _list.AddFirst(value);
            }

            public UndoObject Pop() {
                if (_list.Count == 0)
                    throw new InvalidOperationException("The Stack is empty");
                var value = _list.First.Value;
                _list.RemoveFirst();
                return value;
            }

            public void Clear() {
                if (_list != null) _list.Clear();
            }

            public int Count {
                get { return _list.Count; }
            }
        }

    }
}
